/*
 * Copyright (c) 2021, Polsys Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * File name: battery_manager.c
 * 
 * Description: 
 * 		BatteryMannager "静态类"。更新电池充电状态和参数,适用于有充电管理IC的场景。
 * 
 * Change Logs:
 * Date    		Author       Notes
 * 2021/02/28 	刘言         初版
 * 2022/10/19   刘言    支持只能获取电池电压的情况。
 */

#include "battery_manager.h"
#include "polsys.h"



bit BM_IsCharging = false;
bit BM_DCConnected = false;

NO_INIT pdata u8 BM_Volume;		  //电量百分比 %
pdata u16 BM_Voltage;	  //电压	mV
#if (_BM_USE_TP)
pdata u8 BM_Temperature;  //温度	℃
#endif
#if (_BM_HAS_CC)
pdata u16 BM_ChrgCurrent; //充电电流	mA
#endif

#if ((!_BM_HAS_CC) && (!_BM_HAS_FULL))
NO_INIT u16 mFloatTime;
#endif

static bit mRunning = true;
static pdata u8 mChangeJg = 0;		// 改变参数间隔时间计时
static pdata polsys_task_t mTask;
static bit mTaskInited = false;
static pdata bm_callback_t mCallback = NULL;
static pdata void *mCallbackParam = NULL;
static C51_CODE const u16 mVolToDlTable[] = {3450, 3530, 3670, 3750, 3780, 3810, 3840, 3860, _BM_MAX_BV - 310, _BM_MAX_BV - 250, _BM_MAX_BV - 150, _BM_MAX_BV - 50};
										   0     5     10    20    30    40    50    60    70(3890)    		80(3950)    	 90(4050)    		100(4150)
// static C51_CODE const u16 mVolToDlTable[] = {3550, 3700, 3750, 3780, 3800, 3820, 3840, 3860, _BM_MAX_BV - 310, _BM_MAX_BV - 250, _BM_MAX_BV - 150, _BM_MAX_BV - 50};
// 										 //   0     5     10    20    30    40    50    60    70(3890)    		80(3950)    	 90(4050)    		100(4150)

// 文件内函数申明

static void RefreshStat();
static u8 VoltageToVolume(u16 Voltage);
static void Loop();

// 对外提供的函数

void BM_Init(bool reset)
{
	BM_Voltage = _Bm_GetBv();				 // 获取电池电压值
	if(reset)
	{
		BM_Volume = VoltageToVolume(BM_Voltage); //上电时直接改变电量。
		mFloatTime = 0;
	}
	if(mCallback)mCallback(BMEV_INITED, mCallbackParam);
	if(mTaskInited == false)
	{
		Polsys_TaskInit(&mTask, Loop, 1000);
		mTaskInited = true;
	}
}

void BM_SetRefreshStatus(bool new_status)
{
	if(mRunning != new_status)
	{
		mRunning = true;
		mChangeJg = 255;
		Loop();
		mRunning = new_status;
	}
}

IN_LINE void BM_SetCb(bm_callback_t new_cb, void *param)
{
	mCallback = new_cb;
	mCallbackParam = param;
}

// 以下是内部函数

//刷新充电状态
static void RefreshStat()
{
	if (_Bm_IsDcIn()) //充电器接入
	{
		if (!BM_DCConnected) // 之前未接入
		{
			BM_DCConnected = true;
			if(mCallback)mCallback(BMEV_DC_PULL_IN, mCallbackParam); // 通知充电器接入事件
		}
#if (_BM_HAS_CC)
		if (BM_ChrgCurrent > _BM_DESIGN_CC / 2 || BM_Voltage < _BM_MAX_BV - 200) // 正在充电
#elif (_BM_HAS_FULL)
		if (!_Bm_IsFull()) // 正在充电
#else
		if(BM_Voltage < _BM_MAX_BV - 100 || mFloatTime < _BM_FLOAT_TIME )	// 正在充电
#endif
		{
			if (BM_IsCharging == false)
			{
				BM_IsCharging = true;
				if(mCallback)mCallback(BMEV_START_CHARGE, mCallbackParam);
			}
		}
		else // 已充满
		{
			if (BM_IsCharging == true)
			{
				BM_IsCharging = false;
				BM_Volume = 100;
				if(mCallback)
				{
					mCallback(BMEV_VOLUME_CHANGE, mCallbackParam);
					mCallback(BMEV_CHARGE_FULL, mCallbackParam);
				}
			}
		}
#if ((!_BM_HAS_CC) && (!_BM_HAS_FULL))
		if(BM_Voltage >= _BM_MAX_BV + 100)	// 电压超出设计的充电电压
		{
			mFloatTime = _BM_FLOAT_TIME;
		}
		else if(BM_Voltage >= _BM_MAX_BV - 100)
		{
			if(mFloatTime < _BM_FLOAT_TIME)mFloatTime++;
		}
		else
		{
			mFloatTime = 0;
		}
#endif
	}
	else // 充电器移除了
	{
		if (BM_DCConnected)
		{
#if ((!_BM_HAS_CC) && (!_BM_HAS_FULL))
			if(BM_Voltage < _BM_MAX_BV - 100)
			{
				mFloatTime = 0;
			}
			else if(mFloatTime > 0)mFloatTime--;
#endif
			BM_DCConnected = false;
			BM_IsCharging = false;
			if(mCallback)mCallback(BMEV_DC_PULL_OUT, mCallbackParam);
		}
	}
}

//单纯通过电压粗略计算电量
static u8 VoltageToVolume(u16 Voltage)
{
	u8 temp, i;
	const u16 *table;

	table = mVolToDlTable;

	for (i = 0; i < 12; i++)
	{
		if (Voltage < table[i])
			break;
	}
	i--;
	if (i == 255) //电压小于3V
	{
		temp = 0;
	}
	else if (i >= 2)
	{
		temp = (i - 1) * 10;
		temp += (Voltage - table[i]) * 10 / (table[i + 1] - table[i]);
	}
	else //0,1
	{
		temp = i * 5;
		temp += (Voltage - table[i]) * 5 / (table[i + 1] - table[i]);
	}
	return temp;
}

static void Loop() //1s执行一遍
{
	// static pdata u16 LastVbat = 0;

	if (mRunning)
	{
		u8 update_inte;
#if (_BM_HAS_CC)
		BM_ChrgCurrent = _Bm_GetBcc(); // 获取充电电流
#endif
		BM_Voltage = _Bm_GetBv();	  // 获取电池电压值
		RefreshStat();				  //更新充电状态,充电器是否接入，是否正在充电
		if (BM_IsCharging)
			update_inte = _BM_UD_VOL_INTV_C; //充电时间隔UD_VOL_INTV_C秒更新电量
		else
			update_inte = _BM_UD_VOL_INTV_D; //放电时间隔UD_VOL_INTV_D秒更新电量
		if (mChangeJg >= update_inte)		 //间隔至少temp秒才能改变电池电量
		{
			u8 volume;
			mChangeJg = 0;
			volume = VoltageToVolume(BM_Voltage);
			if (BM_Volume < 99 && volume > BM_Volume && BM_IsCharging) //电量增加了
			{
				BM_Volume++;
				if(mCallback)mCallback(BMEV_VOLUME_CHANGE, mCallbackParam);
			}
			else if (volume < BM_Volume) //电量降低了
			{
				if (volume <= 5)
					BM_Volume = volume;
				else if (BM_Volume - volume >= 5)
					BM_Volume = volume;
				else
					BM_Volume--;
				if(mCallback)mCallback(BMEV_VOLUME_CHANGE, mCallbackParam);
			}
		}
		else
			mChangeJg++;

		//温度监视
		//BATT_GetTemp();
	}
}
